/*********************************************************************
*
* Software License Agreement (BSD License)
*
*  Copyright (c) 2010, Heriot-Watt University, UK.
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the Heriot-Watt University nor the names of
*     its contributors may be used to endorse or promote products
*     derived from this software without specific prior written
*     permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*  POSSIBILITY OF SUCH DAMAGE.
*
*  Author: Joel Cartwright
*
*********************************************************************/

#ifndef MATCHMAKER_ADVANCED_CLIENT_H_
#define MATCHMAKER_ADVANCED_CLIENT_H_

#include <matchmaker/client.h>
#include <matchmaker/service_query.h>

namespace matchmaker
{

/**
 * @brief Advanced interface for advertising and discovering SOA services
 *
 * As a subclass of the simpler Client, this class provides a richer, more complex
 * interface for service discovery. Note that all of the public methods in Client
 * are also available in this class.
 */
class AdvancedClient : public Client
{
public:
  /**
   * @brief Constructor
   *
   * When an AdvancedClient is created, it immediately tries to connect to the matchmaker
   * server. It will not call ros::init, so this should have been done before
   * construction. If you want an AdvancedClient as a member variable in a class, you
   * might want to use AdvancedClientPtr instead and instantiate the AdvancedClient like this:
\verbatim
myClient_ = boost::make_shared<matchmaker::AdvancedClient>();
\endverbatim
   *
   * Note that the AdvancedClient does not start its own thread, but relies on
   * ros::spin() or ros::spinOnce() being called elsewhere in the user code.
   * This is essential for it to process its message queues and timers.
   */
  AdvancedClient();

  /**
   * @brief Destructor
   *
   * When a AdvancedClient is destroyed, it calls shutdown on itself.
   */
  virtual ~AdvancedClient();

  /**
   * @brief Cancels all advertisers, monitors, etc.
   *
   * This will cancel all advertisers and monitors the AdvancedClient had with the
   * matchmaker server, and perform any necessary memory cleanup.
   */
  void shutdown();

  /**
   * @brief Create a service for a named service, with a user callback
   *
   * The callback function will be called once during creation of the
   * service query, and subsequently every time the query results change.
   * If the optional forced callback interval is set, the callback
   * will also occur at the specified interval.
   *
   * As long as at least one active ServiceQuery object is kept in scope
   * by the user, the query will continue to run. To stop querying the
   * service, the user should either destroy or call shutdown on all
   * copies of the ServiceQuery.
   *
   * @param serviceName name of the service to query for
   * @param callback function to call when the service status changes
   * @param forcedCallbackInterval interval to force callback at, in seconds (default=0)
   * @return ServiceQuery query instance
   */
  ServiceQuery queryService(const std::string & serviceName,
      boost::function<void (const ServiceQuery& query)> callback,
      float forcedCallbackInterval = 0);

  /**
   * @brief Create a service query for a named service
   *
   * As long as at least one active ServiceQuery object is kept in scope
   * by the user, the query will continue to run. To stop querying the
   * service, the user should either destroy or call shutdown on all
   * copies of the ServiceQuery.
   *
   * Use of the callback version of monitorService is recommended over
   * this version. The user must repeatedly call getResults on the service
   * monitor with this version.
   *
   * @param serviceName name of the service to query for
   * @return ServiceQuery monitor instance
   */
  ServiceQuery queryService(const std::string & serviceName);

  /**
   * @brief Create a query for all services, with a user callback
   *
   * This is a convenience method, equivalent to passing an empty serviceName
   * to the equivalent queryService method.
   */
  ServiceQuery queryAllServices(boost::function<void (const ServiceQuery& query)> callback,
      float forcedCallbackInterval = 0);

  /**
   * @brief Create a query for all services
   *
   * This is a convenience method, equivalent to passing an empty serviceName
   * to the equivalent queryService method.
   */
  ServiceQuery queryAllServices();


// --------------------------------------------------
// Library users can ignore code below this line.
// --------------------------------------------------

protected:

  bool retrieveAllServices(L_ServiceDetails *services);

  bool retrieveServicesByName(const std::string & serviceName, L_ServiceDetails *services);

};

typedef boost::shared_ptr<AdvancedClient> AdvancedClientPtr;

}

#endif /* MATCHMAKER_ADVANCED_CLIENT_H_ */
